use std::borrow::Cow;

use jni::JNIEnv;
use thiserror::Error;

pub type IoErr = std::io::Error;


#[derive(Debug, Error)]
pub enum AppErr {

    #[error("io:{0}")]
    Io(#[from] IoErr),

    #[error("{0}")]
    Cusom(Cow<'static, str>),

    #[error("proto:{0}")]
    Proto(&'static str),
    
    #[error("jni:{0}")]
    Jni(#[from] jni::errors::Error),
}

impl AppErr {

    pub fn throw_exception(self, env: &mut JNIEnv, clz: &str) {
        _ = env.throw_new(clz, self.to_string());
    }
}

pub fn new_prot_err(msg: &'static str) -> AppErr {
    AppErr::Proto(msg)
}

pub fn new_err(msg: &'static str) -> AppErr {
    AppErr::Cusom(Cow::Borrowed(msg))
}

pub trait ErrWrap<T> {
    
    fn wrap(self) -> Result<T, AppErr>;

    fn wrap_msg(self, msg: &'static str) -> Result<T, AppErr>;
}

impl<T, E: std::error::Error> ErrWrap<T> for Result<T, E> {

    fn wrap(self) -> Result<T, AppErr> {
        match self {
            Ok(v) => Ok(v),
            Err(e) => Err(AppErr::Cusom(Cow::Owned(e.to_string()))),
        }
    }

    fn wrap_msg(self, msg: &'static str) -> Result<T, AppErr> {
        match self {
            Ok(v) => Ok(v),
            Err(e) => {
                let s = format!("{}=>{}", msg, e.to_string());
                Err(AppErr::Cusom(Cow::Owned(s)))
            }
        }
    }
}

impl <T> ErrWrap<T> for Option<T> {

    fn wrap(self) -> Result<T, AppErr> {
        match self {
            Some(v) => Ok(v),
            None => Err(AppErr::Cusom(Cow::Borrowed("option is none")))
        }
    }

    fn wrap_msg(self, msg: &'static str) -> Result<T, AppErr> {
        match self {
            Some(v) => Ok(v),
            None => Err(AppErr::Cusom(Cow::Borrowed(msg)))
        }
    }
}



